unit oRunPropertiesManager;

{
	created   10.4.2010
	author    Miroslav Mintal
	purpose   
}

interface

uses
  oManager, Classes, Generics.Collections, oProcessItem,
  SysUtils, XMLDoc, XMLIntf, oProcessObjects;

type
  ERunPropertiesManager = class(Exception)
  end;

  ENotValidRunPropertiesType = class(ERunPropertiesManager)
  end;

  ERunPropertiesNotExists = class(ERunPropertiesManager)
  end;

  ERunPropertiesAlreadyExists = class(ERunPropertiesManager)
  end;

  TRunPropertiesManager = class(TManager)
    public
      type
        TRunPropertiesType = class(TProcessable)
          strict private
            aName: String;
            aLength: Double;
            aReplications: Double;
            aStats: TList<Boolean>;
      private
        function getStatPedsTimeInModel: Boolean;
        function getStatPeopleInModel: Boolean;
        function getStatPeoplePerArrival: Boolean;
          public
            property Name: String read aName;
            property Length: Double read aLength;
            property Replications: Double read aReplications;
            property Stats: TList<Boolean> read aStats;
            property StatPedsTimeInModel: Boolean read getStatPedsTimeInModel;
            property StatPeopleInModel: Boolean read getStatPeopleInModel;
            property StatPeoplePerArrival: Boolean read getStatPeoplePerArrival;
      published
          private
            constructor Create(paName: String; paLength, paReplications: Double; paStats: TList<Boolean>); overload;
            constructor Create; overload;
            constructor Create(paData: TRunPropertiesData); overload;
            destructor Destroy; override;
            procedure Assign(rhs: TRunPropertiesData);
            procedure Save(var paWhere: IXMLNode);
            procedure Load(paFrom: IXMLNode);
        end;
    private
      aRunProperties: TList<TRunPropertiesType>;
      function search(paName: String): TRunPropertiesType;
      procedure resetList;
      function exists(paName: String): boolean;
    public
      property RunProperties: TList<TRunPropertiesType> read aRunProperties;
      constructor Create(paMaster: TManager);
      destructor Destroy; override;
      function ProcessObject(paItem: TProcessItem):TProcessItem; override; final;
  end;

implementation

uses
  oProcessObjectConstants;

resourcestring eRunPropManNotValidType = 'not a valid processing type';
resourcestring eRunPropManNotValidConstant = 'not a valid constant';
resourcestring eRunPropManFoundDuplicity = 'entity already exists';
resourcestring eRunPropManRunPropertiesNotFound = 'entity not found';

{ TRunPropertiesManager }

constructor TRunPropertiesManager.Create(paMaster: TManager);
begin
  aMaster := paMaster;
  aRunProperties := TList<TRunPropertiesType>.Create;
end;

destructor TRunPropertiesManager.Destroy;
var
  RunPropertie: TRunPropertiesType;
begin
  for RunPropertie in RunProperties do
    RunPropertie.Free;
  aRunProperties.Free;
  inherited;
end;

function TRunPropertiesManager.exists(paName: String): boolean;
var
  RunPropertie: TRunPropertiesType;
begin
  result := false;
  for RunPropertie in RunProperties do
    if RunPropertie.Name = paName then
    begin
      result := true;
      break;
    end;

end;

function TRunPropertiesManager.ProcessObject(paItem: TProcessItem): TProcessItem;
var
  RunProperty: TRunPropertiesType;
  node: IXMLNode;
  strings : TStringList;

begin
  result := nil;
  case paItem.Code of

    PO_RUNPROPMAN_INSERT:
    begin
      try
        if not(paItem.Data is TRunPropertiesData) then raise ENotValidRunPropertiesType.Create(eRunPropManNotValidType);
        if exists((paItem.Data as TRunPropertiesData).NameData) then raise ERunPropertiesAlreadyExists.Create(eRunPropManFoundDuplicity);
        RunProperties.Add(TRunPropertiesType.Create(paItem.Data as TRunPropertiesData));
        aMaster.ProcessObject(TProcessItem.create(PO_TREE_INSERT_RUNPROP_LAYER,TString.Create((paItem.Data as TRunPropertiesData).NameData)));
        aMaster.ProcessObject(TProcessItem.create(PO_PROJECT_SAVE_RUN_PROPS, nil));
        paItem.Free;
        result := nil;
      except
        on E:ENotValidRunPropertiesType do raise ERunPropertiesManager.Create(eRunPropManNotValidType);
        on E:ERunPropertiesManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_RUNPROPMAN_REMOVE:
    begin
      try
        if not(paItem.Data is TString) then raise ENotValidRunPropertiesType.Create(eRunPropManNotValidType);
        RunProperty := search((paItem.Data as TString).String_);
        if RunProperty <> nil then
          begin
            aMaster.ProcessObject(TProcessItem.create(PO_TREE_REMOVE_RUNPROP_LAYER,TString.Create(RunProperty.Name)));
            RunProperties.Extract(RunProperty).Free;
            aMaster.ProcessObject(TProcessItem.create(PO_PROJECT_SAVE_RUN_PROPS, nil));
          end;
        paItem.Data.Free;
        paItem.Free;
      except
        on E:ENotValidRunPropertiesType do raise ERunPropertiesManager.Create(eRunPropManNotValidType);
      end;
    end;

    PO_RUNPROPMAN_GET_NAMES : begin
      strings := TStringList.Create;
      for RunProperty in aRunProperties do
        strings.Add(RunProperty.Name);
      Result := TProcessItem.create(PO_SUCCESS, TProcessingStrings.Create(strings));
      paItem.Data.Free;
      paItem.Free;
    end;

    PO_RUNPROPMAN_EDIT:
    begin
      try
        if not(paItem.Data is TRunPropertiesData) then raise ENotValidRunPropertiesType.Create(eRunPropManNotValidType);
        RunProperty := search((paItem.Data as TRunPropertiesData).NameData);
        if RunProperty = nil then raise ERunPropertiesNotExists.Create('');
        RunProperty.Assign((paItem.Data as TRunPropertiesData));
        aMaster.ProcessObject(TProcessItem.create(PO_PROJECT_SAVE_RUN_PROPS, nil));
        paItem.Free;
        result := nil;
      except
        on E:ENotValidRunPropertiesType do raise ERunPropertiesManager.Create(eRunPropManNotValidType);
        on E:ERunPropertiesNotExists do raise ERunPropertiesManager.Create(eRunPropManRunPropertiesNotFound);
      end;
    end;

    PO_RUNPROPMAN_SAVE:
    begin
        try
        if not(paItem.Data is TProcessingXML) then raise ENotValidRunPropertiesType.Create(eRunPropManNotValidType);
        node := ((paItem.Data) as TProcessingXML).Node;
        for RunProperty in aRunProperties do RunProperty.Save(node);
        result := TProcessItem.create(PO_SUCCESS, TProcessingXML.Create(node));
        paItem.Data.Free;
        paItem.Free;
      except
        on E:ENotValidRunPropertiesType do raise ERunPropertiesManager.Create(eRunPropManNotValidType);
      end;
    end;

    PO_RUNPROPMAN_LOAD:
    begin
      try
        if not(paItem.Data is TProcessingXML) then raise ENotValidRunPropertiesType.Create(eRunPropManNotValidType);
        resetList;
        node := (paItem.Data as TProcessingXML).Node.ChildNodes.First;
        while node <> nil do
        begin
          RunProperty := TRunPropertiesType.Create;
          RunProperty.Load(node);
          aRunProperties.Add(RunProperty);
          node := node.NextSibling;
        end;
        paItem.Data.Free;
        paItem.Free;
        result := nil;
      except
        on E:ENotValidRunPropertiesType do raise ERunPropertiesManager.Create(eRunPropManNotValidType);
      end;
    end;

    PO_RUNPROPMAN_GET_RUN_PROPERTIES:
    begin
      try
        if not(paItem.Data is TString) then raise ENotValidRunPropertiesType.Create(eRunPropManNotValidType);
        RunProperty := search((paItem.Data As TString).String_);
        if RunProperty = nil then raise ERunPropertiesNotExists(eRunPropManRunPropertiesNotFound);
        paItem.Data.Free;
        paItem.Free;
        Result := TProcessItem.create(PO_SUCCESS,RunProperty);
      except
        Result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_RUNPROPMAN_EXISTS:
    begin
      try
        if not(paItem.Data is TString) then raise ENotValidRunPropertiesType.Create(eRunPropManNotValidType);
        RunProperty := search((paItem.Data as TString).String_);
        if RunProperty <> nil
          then Result := TProcessItem.create(PO_SUCCESS,RunProperty)
          else Result := TProcessItem.create(PO_FAILURE,nil);
        paItem.Data.Free;
        paItem.Free;
      except
        Result := TProcessItem.create(PO_FAILURE,nil);
     end;

    end;

  end; //Case
end; //method

procedure TRunPropertiesManager.resetList;
var
  RunPropertie: TRunPropertiesType;
begin
  for RunPropertie in aRunProperties do RunPropertie.Free;
  aRunProperties.Free;
  aRunProperties := TList<TRunPropertiesType>.Create;
end;

function TRunPropertiesManager.search(paName: String): TRunPropertiesType;
var
  RunPropertie: TRunPropertiesType;
begin
  for RunPropertie in RunProperties do
    if RunPropertie.Name = paName then
    begin
      //we found it, let's return it and exit function
      result := RunPropertie;
      exit;
    end;
  result := nil;
end;

{ TRunPropertiesManager.TRunPropertiesType }

constructor TRunPropertiesManager.TRunPropertiesType.Create(paName: String; paLength, paReplications: Double; paStats: TList<Boolean>);
begin
  inherited create;
  aStats := paStats;
  aName := paName;
  aLength := paLength;
  aReplications := paReplications;
end;

constructor TRunPropertiesManager.TRunPropertiesType.Create;
begin
  inherited create;
  aStats := TList<Boolean>.create;
  aName := '';
  aReplications := 0;
  aLength := 0;
end;

procedure TRunPropertiesManager.TRunPropertiesType.Assign(rhs: TRunPropertiesData);
begin
  aStats := rhs.Stats;
  aLength := rhs.Length;
  aReplications := rhs.Replications;
  aName := rhs.NameData;
end;

constructor TRunPropertiesManager.TRunPropertiesType.Create(paData: TRunPropertiesData);
begin
  inherited create;
  with paData do
  begin
    aStats := paData.Stats;
    aName := NameData;
    aLength := Length;
    aReplications := Replications;
  end;
end;

destructor TRunPropertiesManager.TRunPropertiesType.Destroy;
begin
  aStats.Free;
  inherited;
end;

function TRunPropertiesManager.TRunPropertiesType.getStatPedsTimeInModel: Boolean;
begin
  if aStats.Count < 0
    then result := false
    else result := aStats[0];
end;

function TRunPropertiesManager.TRunPropertiesType.getStatPeopleInModel: Boolean;
begin
  if aStats.Count < 1
    then result := false
    else result := aStats[1];
end;

function TRunPropertiesManager.TRunPropertiesType.getStatPeoplePerArrival: Boolean;
begin
  if aStats.Count < 2
    then result := false
    else result := aStats[2];
end;

procedure TRunPropertiesManager.TRunPropertiesType.Load(paFrom: IXMLNode);
var
  RPTypeNode,RPTypeAttribute: IXMLNode;
begin
  RPTypeNode := paFrom;
  if RPTypeNode.HasAttribute('name') then aName := RPTypeNode.Attributes['name'];
  RPTypeAttribute := RPTypeNode.ChildNodes.FindNode('length');
  if RPTypeAttribute.HasAttribute('value') then aLength := RPTypeAttribute.Attributes['value'];
  RPTypeAttribute := RPTypeNode.ChildNodes.FindNode('replications');
  if RPTypeAttribute.HasAttribute('value') then aReplications := RPTypeAttribute.Attributes['value'];
  RPTypeNode := RPTypeNode.ChildNodes.FindNode('statistics');
  if RPTypeNode <> nil then
    begin
      RPTypeAttribute := RPTypeNode.ChildNodes.First;
      while RPTypeAttribute <> nil do
        begin
          if RPTypeAttribute.HasAttribute('value') then aStats.Add(RPTypeAttribute.Attributes['value']);
          RPTypeAttribute := RPTypeAttribute.NextSibling;
        end;
    end;
end;

procedure TRunPropertiesManager.TRunPropertiesType.Save(var paWhere: IXMLNode);
var
  RPTypeNode,RPTypeAttribute: IXMLNode;
  i: Integer;
begin
  RPTypeNode := paWhere.AddChild('RunProperty');
  RPTypeNode.Attributes['name'] := aName;
  RPTypeAttribute := RPTypeNode.AddChild('length');
  RPTypeAttribute.Attributes['value'] := aLength;
  RPTypeAttribute := RPTypeNode.AddChild('replications');
  RPTypeAttribute.Attributes['value'] := aReplications;
  RPTypeNode := RPTypeNode.AddChild('statistics');
  for i := 0 to aStats.Count - 1 do
    begin
      RPTypeAttribute := RPTypeNode.AddChild('stat' + IntToStr(i));
      RPTypeAttribute.Attributes['value'] := aStats[i];
    end;
end;

end.
